package com.flute.search.service;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.security.InvalidParameterException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.flute.framework.Flute;
import com.flute.framework.FluteMonitor;
import com.flute.framework.exception.ConfigurationParseException;
import com.flute.framework.exception.SearchException;
import com.flute.framework.monitor.EventLogger;
import com.flute.framework.monitor.MonitedValue;
import com.flute.framework.search.ISearcher;
import com.flute.framework.search.SearchFilter;
import com.flute.framework.search.SearchRequest;
import com.flute.search.constants.SearchServiceConstants;
import com.flute.tools.util.ExceptionUtil;

/**
 * 搜索服务的Servlet
 */
public class SearchService extends HttpServlet {
	private static final long serialVersionUID = 6394153484613563168L;

	/**
	 * Constructor of the object.
	 */
	public SearchService() {
		super();
	}

	/**
	 * The doGet method of the servlet. <br>
	 * 
	 * This method is called when a form has its tag value method equals to get.
	 * 
	 * @param request
	 *            the request send by the client to the server
	 * @param response
	 *            the response send by the server to the client
	 * @throws ServletException
	 *             if an error occurred
	 * @throws IOException
	 *             if an error occurred
	 */
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doPost(request, response);
	}

	/**
	 * The doPost method of the servlet. <br>
	 * 
	 * This method is called when a form has its tag value method equals to
	 * post.
	 * 
	 * @param request
	 *            the request send by the client to the server
	 * @param response
	 *            the response send by the server to the client
	 * @throws ServletException
	 *             if an error occurred
	 * @throws IOException
	 *             if an error occurred
	 */
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// info("搜索服务开始...");

		response.setCharacterEncoding(SearchServiceConstants.CHARSET_UTF8);

		String searcher = request.getParameter(SearchServiceConstants.SEARCHER);
		// info("搜索器是" + searcher);

		String keyword = request.getParameter(SearchServiceConstants.KEYWORD);
		// info("关键字是" + keyword);

		String page = request.getParameter(SearchServiceConstants.PAGE);
		// info("页数是" + page);

		String num = request.getParameter(SearchServiceConstants.NUM);
		// info("每页显示数量是" + num);

		String sorter = request.getParameter(SearchServiceConstants.SORTER);
		// info("排序方式是" + sorter);

		String client = request
				.getParameter(SearchServiceConstants.CLIENT_CODE);
		client = client == null || "".equals(client) ? "-1" : client;

		Map<String, String> filterMap = new ConcurrentHashMap<String, String>();

		// 初始化过滤器的Map
		initFilterMap(request, filterMap);

		// 检查参数
		if (isNullOrEmpty(searcher) || isNullOrEmpty(keyword)
				|| isNullOrEmpty(page) || isNullOrEmpty(num)) {
			error("无效的参数,searcher,keyword,page,num参数不能为空,请检查再试");
			throw new InvalidParameterException(
					"Invalid parameter please check it and retry");
		}

		PrintWriter out = response.getWriter();
		try {
			ISearcher searcher1 = Flute.getInstance().getSearcher(searcher);
			// 设置SearchRequest
			SearchRequest sr = populateSearchRequest(searcher, keyword, page,
					num, sorter, client, filterMap);
			if (searcher1 == null) {
				throw new ConfigurationParseException("不能找到对应的searcher"
						+ searcher + "，请检查后再试");
			}
			String result = searcher1.search(sr);
			out.print(result);
			// info("搜索的结果是:" + result);
			// info("搜索服务结束...");
			out.flush();
			out.close();
		} catch (ConfigurationParseException e) {
			error("配置解析器异常:" + ExceptionUtil.getExceptionContent(e));
			response.sendError(HttpServletResponse.SC_BAD_REQUEST,
					"不能找到对应的searcher，请检查后再试");
		} catch (SearchException e) {
			error("搜索异常" + ExceptionUtil.getExceptionContent(e));
		} finally {
			if (out != null) {
				out.close();
			}
		}
	}

	private void error(String message) {
		EventLogger.error(new MonitedValue(message),
				FluteMonitor.getSearcherKey());
	}

	private SearchRequest populateSearchRequest(String searcher,
			String keyword, String page, String num, String sorter,
			String client, Map<String, String> filterMap)
			throws UnsupportedEncodingException {
		// 设置SearchFilter
		SearchRequest sr = new SearchRequest();
		sr.setKeyword(keyword);
		sr.setNumberPerPage(Integer.parseInt(num));
		sr.setPageNumber(Integer.parseInt(page));
		setSorter(sorter, sr);
		sr.setSearcherName(searcher);
		sr.setClient(client);
		setFilter(filterMap, sr);
		return sr;
	}

	private void setFilter(Map<String, String> filterMap, SearchRequest sr) {
		if (!filterMap.isEmpty()) {
			SearchFilter filter = populateFilter(filterMap);
			sr.setSearchFilter(filter);
		}
	}

	private void setSorter(String sorter, SearchRequest sr) {
		if (!isNullOrEmpty(sorter)) {
			sr.setSorter(sorter);
		}
	}

	private SearchFilter populateFilter(Map<String, String> filterMap) {
		SearchFilter filter = new SearchFilter();
		for (Entry<String, String> entry : filterMap.entrySet()) {
			String[] values = entry.getValue().split(",");
			for (String value : values) {
				filter.addFilter(entry.getKey(), value);
			}
		}
		return filter;
	}

	@SuppressWarnings("unchecked")
	private void initFilterMap(HttpServletRequest request,
			Map<String, String> filterMap) {
		Enumeration<String> names = request.getParameterNames();
		while (names.hasMoreElements()) {
			String name = names.nextElement();
			String prefix = SearchServiceConstants.FILTER
					+ SearchServiceConstants.UNDERLINE;
			if (name.startsWith(prefix)) {
				String fieldName = name.substring(7);
				if (filterMap.containsKey(fieldName)) {
					String value = filterMap.get(fieldName) + ","
							+ request.getParameter(name);
					filterMap.put(fieldName, value);
				} else {
					filterMap.put(fieldName, request.getParameter(name));
				}
			}
		}
	}

	private boolean isNullOrEmpty(String s) {
		return s == null || s.trim().equals(SearchServiceConstants.EMPTY);
	}

}
